//build:20240716
//This worker is designed to simplify the use of the micro-light communication protocol for TCP components. Users only need to subscribe to EventBus events to listen for TCP data.
import log from './dxLogger.js'
import tcp from './dxTcp.js'
import common from './dxCommon.js'
import std from './dxStd.js'
import dxMap from './dxMap.js'
import net from './dxNet.js'
import * as os from "os"
const map = dxMap.get('default')
const id = "{{id}}"
const options = map.get("__vgtcp__run_init" + id)
const timeout = 100
const longTimeout = 500
let connected = false

function run() {
    tcp.create(options.ip, options.port, options.timeout, options.heartEn, options.heartTime, options.id)
    log.info('vg tcp start......,id =', id)
    os.sleep(1000)
    std.setInterval(() => {
        try {
            if (tcp.isConnect(options.id) && net.getStatus().connected) {
                if (!connected) {
                    _fireChange(true)
                }
            } else {
                if (connected) {
                    _fireChange(false)
                }
                os.sleep(1000)
            }
        } catch (error) {
            log.error(error)
        }
    }, 3000)
    std.setInterval(() => {
        if (connected) {
            // Receive data mode
            if (options.passThrough) {
                // Pass-through mode
                passThrough()
            } else {
                // Low-light communication protocol mode
                receive()
            }
        }
    }, 10)
}

// Pass-through mode
function passThrough() {
    let pack = [];
    let buffer = readOne()
    while (buffer !== null) {
        pack.push(buffer)
        os.sleep(10)
        buffer = readOne()
    }
    if (pack.length !== 0) {
        __bus.fire(tcp.VG.RECEIVE_MSG + options.id, pack)
    }
}

function receive() {
    //The first two bytes must be 55aa
    let buffer = readOne()
    if (buffer === null) {
        return;
    }
    if (buffer == 85) {//0x55
        buffer = readOne()
        if (buffer != 170) {//0xaa
            return;
        }
    } else {
        return;
    }
    let pack = {};
    // Read command word (occupies 1 byte)
    buffer = readOne()
    if (buffer === null) {
        return;
    }
    pack.cmd = buffer
    if (options.result) {
        // Read the result word (occupies 1 byte)
        buffer = readOne()
        if (buffer === null) {
            return;
        }
        pack.result = buffer;
    } else {
        pack.result = 0//0 does not affect the calculation result of bcc.
    }
    // The command header has been parsed; the length word (occupying 2 bytes) is now being read.
    let len1 = readOne()
    if (len1 === null) {
        return;
    }
    let len2 = readOne()
    if (len2 === null) {
        return;
    }
    // Parse the length word to obtain the length of the data field.
    let len = len1 + len2 * 256
    // Read the specified data length based on the length word.
    pack.length = len
    if (len > 0) {
        buffer = tcp.receive(len, longTimeout, options.id)
        if (buffer === null) {
            return;
        }
        pack.data = Array.from(buffer);
    } else {
        pack.data = 0
    }
    // Read 1 byte of parity bit
    buffer = readOne()
    if (buffer === null) {
        return;
    }
    let bcc = valid(pack, buffer)
    let res = { cmd: int2hex(pack.cmd), length: pack.length, bcc: bcc }
    if (pack.length > 0) {
        res.data = common.arrToHex(pack.data)
    }
    if (options.result) {
        res.result = int2hex(pack.result)
    }
    __bus.fire(tcp.VG.RECEIVE_MSG + options.id, res)
}
function valid(pack, bcc) {
    let temp = common.calculateBcc([0x55, 0xaa, pack.cmd, pack.result, pack.length % 256, Math.floor(pack.length / 256)].concat(pack.data))
    return temp === bcc
}
function readOne() {
    let buffer = tcp.receive(1, timeout, options.id)
    if (buffer) {
        return parseInt(buffer);
    }
    return null
}
function int2hex(num) {
    return num.toString(16).padStart(2, '0')
}
function _fireChange(status) {
    __bus.fire(tcp.VG.CONNECTED_CHANGED + options.id, status ? 'connected' : 'disconnected')//When you call `bus.newworker`, you will import `eventbus` as `__bus`.
    connected = status
}
run()